<template>
  <el-form
      class="search-table-form"
      :model="params"
      :inline="inline"
      ref="form"
      @submit.native.prevent="searchHandler()"
      :label-width="labelWidth ? (labelWidth + 'px') : ''"
  >
    <el-row
        :gutter="48"
        style="margin: 0"
        :class="{'single-input' : forms.length === 1, 'hasBackBtn': hasBackBtn}"
    >
      <template v-for="(form, index) in forms">
        <el-col :md="16" :key="str+ index + 's'" v-if="hasBackBtn">
            <slot name="backBtn"></slot>
        </el-col>
        <el-col :md="8" :key="str+ index" v-show="advanced || index<2">
          <el-form-item
              :prop="(form.itemType != 'daterange' && form.itemType != 'rangePrice') ? form.prop : (datePrefix + index)"
              :rules="form.rules || []"
              :label-width="form.labelWidth ? (form.labelWidth + 'px') : ''"
              :label="form.label"
          >
            <el-input
                @keyup.enter.native="searchHandler()"
                v-if="form.itemType === 'input' || form.itemType === undefined"
                v-model="params[form.modelValue]"
                :size="form.size ? form.size : size"
                :readonly="form.readonly"
                :disabled="form.disabled"
                :placeholder="form.placeholder"
                :clearable="true"
                @clear="searchHandler"
                style="width: 100%;"
            />
            <el-input
                @keyup.enter.native="searchHandler()"
                v-else-if="form.itemType === 'inputNumber'"
                v-model="params[form.modelValue]"
                :size="form.size ? form.size : size"
                :readonly="form.readonly"
                :disabled="form.disabled"
                :placeholder="form.placeholder"
                :clearable="true"
                @keyup.native="check_num(form.modelValue)"
                style="width: 100%;"
            />
            <!--        :style="itemStyle + (form.itemWidth ? `width: ${form.itemWidth}px;` : '')"-->
            <el-select v-else-if="form.itemType === 'select' && form.selectChange"
                       v-model="params[form.modelValue]"
                       :size="form.size ? form.size : size"
                       filterable
                       :disabled="form.disabled"
                       :placeholder="form.placeholder"
                       @change="form.selectChange(params[form.modelValue], params)"
                       style="width: 100%;">
              <el-option v-for="(option, optionIndex) in form.options" :key="optionIndex + '_local'"
                         :value="(typeof option === 'object') ? option[form.valueKey || 'value'] : option"
                         :label="(typeof option === 'object') ? option[form.labelKey || 'label'] : option"/>
              <el-option v-for="(op, opIndex) in selectOptions[selectOptionPrefix + index]" :key="opIndex + '_remote'"
                         :value="(typeof op === 'object') ? op[form.valueKey || 'value'] : op"
                         :label="(typeof op === 'object') ? op[form.labelKey || 'label'] : op"/>
            </el-select>
            <el-select v-else-if="form.itemType === 'select' && form.remoteMethod"
                       v-model="params[form.modelValue]"
                       :multiple="form.multiple || false"
                       :size="form.size ? form.size : size"
                       filterable
                       remote
                       :clearable="form.clearable || false"
                       :loading="form.loading"
                       :disabled="form.disabled"
                       :placeholder="form.placeholder"
                       :remote-method="form.remoteMethod"
                       @change="searchHandler"
                       style="width: 100%;">
              <el-option v-for="(option, optionIndex) in form.options" :key="optionIndex + '_local'"
                         :value="(typeof option === 'object') ? option[form.valueKey || 'value'] : option"
                         :label="(typeof option === 'object') ? option[form.labelKey || 'label'] : option"/>
              <el-option v-for="(op, opIndex) in selectOptions[selectOptionPrefix + index]" :key="opIndex + '_remote'"
                         :value="(typeof op === 'object') ? op[form.valueKey || 'value'] : op"
                         :label="(typeof op === 'object') ? op[form.labelKey || 'label'] : op"/>
            </el-select>
            <el-select
                v-else-if="form.itemType === 'select'"
                v-model="params[form.modelValue]"
                :multiple="form.multiple || false"
                :clearable="form.clearable || false"
                :reserve-keyword="form.reserveKeyword || false"
                :size="form.size ? form.size : size"
                :disabled="form.disabled"
                :placeholder="form.placeholder"
                @change="searchHandler"
                style="width: 100%"
            >
              <el-option
                  v-for="(option, optionIndex) in form.options"
                  :key="optionIndex + '_local'"
                  :value="(typeof option === 'object') ? option[form.valueKey || 'value'] : option"
                  :label="(typeof option === 'object') ? option[form.labelKey || 'label'] : option"
              />
              <el-option
                  v-for="(op, opIndex) in selectOptions[selectOptionPrefix + index]"
                  :key="opIndex + '_remote'"
                  :value="(typeof op === 'object') ? op[form.valueKey || 'value'] : op"
                  :label="(typeof op === 'object') ? op[form.labelKey || 'label'] : op"
              />
            </el-select>
            <al-selector-search
                v-else-if="form.itemType === 'area'"
                v-model="params[form.modelValue]"
                :level="form.level"
                size="small"
                type="text"
            />
            <el-date-picker
                v-else-if="form.itemType === 'date-month'"
                v-model="params[form.modelValue]"
                type="month"
                :placeholder="form.placeholder"
                :size="form.size ? form.size : size"
                :disabled="form.disabled"
                :readonly="form.readonly"
                :editable="form.editable"
                style="width: 100%"
                :picker-options="form.pickerOptions || {}"
            />
            <el-date-picker
                v-else-if="form.itemType === 'date'"
                v-model="params[form.modelValue]"
                type="date"
                :placeholder="form.placeholder"
                :size="form.size ? form.size : size"
                :disabled="form.disabled"
                :readonly="form.readonly"
                :editable="form.editable"
                style="width: 100%"
                :picker-options="form.pickerOptions || {}"
            />
            <el-date-picker
                v-else-if="form.itemType === 'daterange'"
                v-model="params[form.modelValue]"
                :size="form.size ? form.size : size"
                type="daterange"
                @change="date => changeDate(date, form.prop[0], form.prop[1])"
                :disabled="form.disabled"
                :readonly="form.readonly"
                :editable="form.editable"
                :startPlaceholder="form.startPlaceholder"
                :endPlaceholder="form.endPlaceholder"
                style="width: 100%"
                :picker-options="form.pickerOptions || {}"
            />
            <div  v-else-if="form.itemType === 'rangePrice'" style="display: flex;align-items: center">
              <el-input-number
                  v-model="params[form.prop[0]]"
                  :size="form.size ? form.size : size"
                  :readonly="form.readonly"
                  :disabled="form.disabled"
                  :placeholder="form.startPlaceholder"
                  :clearable="true"
                  :controls="false"
                  @clear="searchHandler"
                  @keyup.enter.native="searchHandler()"
                  :precision="2"
                  :min="0"
                  style="width: 100%;"
              />
              <span style="padding: 0 12px">~</span>
              <el-input-number
                  v-model="params[form.prop[1]]"
                  :size="form.size ? form.size : size"
                  :readonly="form.readonly"
                  :disabled="form.disabled"
                  :placeholder="form.endPlaceholder"
                  :clearable="true"
                  :controls="false"
                  :min="0"
                  :precision="2"
                  @clear="searchHandler"
                  @keyup.enter.native="searchHandler()"
                  style="width: 100%;"
              />
            </div>
          </el-form-item>
          <div class="search-btns" v-if="forms.length === 1">
            <slot name="download"></slot>
            <el-button
                type="primary"
                :size="size"
                icon="el-icon-search"
                v-if="showSearchBtn"
                @click="searchHandler"
                :loading="submitLoading"
            >
              {{ submitBtnText }}
            </el-button>
            <el-button
                type="default"
                :plain="false"
                :size="size"
                icon="el-icon-refresh"
                v-if="showResetBtn"
                @click="resetForm"
                :loading="submitLoading"
            >
              {{ resetBtnText }}
            </el-button>
            <!--          <a @click="toggleAdvanced" style="margin-left: 8px">-->
            <!--            {{ advanced ? '收起' : '展开' }}-->
            <!--            <i :class="advanced ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>-->
            <!--          </a>-->
            <a @click="toggleAdvanced" style="margin-left: 8px" v-if="forms.length > 3">
              {{ advanced ? '收起' : '展开' }}
              <i :class="[advanced ? 'el-icon-arrow-up' : 'el-icon-arrow-down']"></i>
              <!--            <a-icon :type="advanced ? 'up' : 'down'"/>-->
            </a>
          </div>
        </el-col>
      </template>
      <el-col v-if="forms.length>1" :span="8" :offset="advanced ? getOffset(forms.length, 8) : 0">
        <div class="search-btns">
          <slot name="download"></slot>
          <el-button
              type="primary"
              :size="size"
              icon="el-icon-search"
              v-if="showSearchBtn"
              @click="searchHandler"
              :loading="submitLoading"
          >
            {{ submitBtnText }}
          </el-button>
          <el-button
              type="primary"
              :plain="false"
              :size="size"
              icon="el-icon-refresh"
              v-if="showResetBtn"
              @click="resetForm"
              :loading="submitLoading"
          >
            {{ resetBtnText }}
          </el-button>
          <!--          <a @click="toggleAdvanced" style="margin-left: 8px">-->
          <!--            {{ advanced ? '收起' : '展开' }}-->
          <!--            <i :class="advanced ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>-->
          <!--          </a>-->
          <a @click="toggleAdvanced" style="margin-left: 8px" v-if="forms.length >= 3">
            {{ advanced ? '收起' : '展开' }}
            <i :class="[advanced ? 'el-icon-arrow-up' : 'el-icon-arrow-down']"></i>
            <!--            <a-icon :type="advanced ? 'up' : 'down'"/>-->
          </a>
        </div>
      </el-col>
    </el-row>
    <!--      <el-form-item style="float: left">
&lt;!&ndash;        <span style="font-size: 16px;font-weight: bold;">{{pageName}}</span>&ndash;&gt;
        <slot name="formButton"></slot>
      </el-form-item>-->
  </el-form>
</template>

<script>
import {debounce} from '@/utils/utils';

const sizeValidator = value => {
    const methodTypes = ['large', 'small', 'mini'];
    const valid = methodTypes.indexOf(value.toLowerCase()) !== -1 || value === '';
    if (!valid) {
        throw new Error('Size must be one of [\'large\', \'small\', \'mini\']');
    }
    return valid;
};
export default {
    name: 'SearchForm',
    props: {
        expand: {
            type: Boolean,
            default: false
        },
        size: {
            type: String,
            default: '',
            validator: sizeValidator
        },
        showResetBtn: {
            type: Boolean,
            default: false
        },
        showSearchBtn: {
            type: Boolean,
            default: true
        },
        autoHeight: {
            type: Boolean,
            default: false
        },
        inline: {
            type: Boolean,
            default: false
        },
        fuzzy: {
            type: Boolean,
            default: false
        },
        labelWidth: Number,
        itemWidth: Number,
        submitHandler: Function,
        submitLoading: {
            type: Boolean,
            default: false
        },
        submitBtnText: {
            type: String,
            default: '查询'
        },
        resetBtnText: {
            type: String,
            default: '重置'
        },
        resetBtnCallback: Function,
        forms: {
            type: Array,
            required: true
        },
        hasBackBtn: {
            type: Boolean,
            default: false
        }
    },
    data () {
        const {forms, fuzzy} = this.$props;
        const datePrefix = 'daterange-prefix';
        const selectOptionPrefix = 'select-option-prefix';
        let dataObj = {
            selectOptions: {}
        };
        let params = {};
        let format = {};
        let fuzzyOps = {};
        forms.forEach((v, i) => {
            const propType = typeof v.prop;
            if (propType === 'string' && v.itemType !== 'area') {
                v.modelValue = v.prop;
                params[v.prop] = '';
                fuzzyOps[v.prop] = v.fuzzy ? v.fuzzy : fuzzy;
                if (v.format) {
                    format[v.prop] = v.format;
                }
            } else if (
                propType === 'object' && Object.prototype.toString.call(v.prop) === '[object Array]'
            ) {
                v.prop.forEach(vv => {
                    if (v.itemType === 'rangePrice') {
                        params[vv] = undefined;
                    } else {
                        params[vv] = '';
                    }
                    if (v.format) {
                        format[vv] = v.format;
                    }
                    fuzzyOps[vv] = v.fuzzy ? v.fuzzy : fuzzy;
                });
            } else {
                v.modelValue = v.prop;
                params[v.prop] = [];
            }
            if (v.itemType === 'daterange') {
                params[datePrefix + i] = '';
                v.modelValue = datePrefix + i;
            }
            if (v.itemType === 'select' && (v.selectFetch || v.selectUrl)) {
                const dataKey = selectOptionPrefix + i;
                dataObj.selectOptions[dataKey] = [];
                const {$axios} = this;
                if (!v.selectMethod) {
                    v.selectMethod = 'get';
                }
                this.getRemoteData({
                    fetch: v.selectFetch
                        ? v.selectFetch
                        : () => {
                            return $axios[v.selectMethod](
                                v.selectUrl,
                                v.selectMethod.toLowerCase() === 'get'
                                    ? {params: v.selectParams}
                                    : v.selectParams
                            );
                        },
                    dataKey,
                    resultField: v.selectResultField || 'result',
                    resultHandler: v.selectResultHandler
                });
            }
        });
        return {
            // 高级搜索 展开/关闭
            // advanced: false,
            advanced: this.expand,
            params,
            datePrefix,
            selectOptionPrefix,
            ...dataObj,
            format,
            fuzzyOps,
            pageName: this.$route.meta.title,
            str: Math.random().toString(36).slice(-6)
        };
    },
    computed: {
        itemStyle () {
            const {itemWidth} = this;
            if (itemWidth) {
                return `width: ${itemWidth}px;`;
            }
            return '';
        }
    },
    methods: {
        isArray (value) {
            return (
                typeof value === 'object' &&
          Object.prototype.toString.call(value) === '[object Array]'
            );
        },
        searchHandler () {
            this.getParams((error, params) => {
                if (!error) {
                    const {submitHandler} = this;
                    if (submitHandler) {
                        params.page = 1;
                        submitHandler(params);
                    } else {
                        throw new Error('Need to set attribute: submitHandler !');
                    }
                }
            });
        },
        getParamFuzzy () {
            return this.fuzzyOps;
        },
        getParams (callback) {
            this.$refs['form'].validate(valid => {
                if (valid) {
                    const {params, datePrefix, format} = this;
                    let formattedForm = {};
                    Object.keys(params).forEach(v => {
                        if (v.indexOf(datePrefix) === -1) {
                            formattedForm[v] = format[v]
                                ? format[v](params[v], v)
                                : params[v];
                        }
                    });
                    if (callback) {
                        callback(null, formattedForm);
                    }
                } else {
                    if (callback) {
                        callback(new Error());
                    }
                }
            });
        },
        // 强制置空所有参数
        resetFields () {
            console.log(this.params);
            for (let val in this.params) {
                if (Array.isArray(this.params[val])) {
                    this.params[val] = [];
                    console.log(this.params[val]);
                } else {
                    this.params[val] = '';
                }
            }
        },
        resetForm () {
            if (this.forms.some(s => s.itemType === 'rangePrice')) {
                let data = this.forms.find(s => s.itemType === 'rangePrice');
                this.params[data.prop[0]] = undefined;
                this.params[data.prop[1]] = undefined;
            }
            if (this.forms.some(s => s.itemType === 'daterange')) {
                let data = this.forms.find(s => s.itemType === 'daterange');
                this.params[data.prop[0]] = '';
                this.params[data.prop[1]] = '';
            }
            this.$refs['form'].resetFields();
            console.log(this.params);
            const {resetBtnCallback} = this;
            if (resetBtnCallback) {
                resetBtnCallback();
            }
        },
        changeDate (date, startDate, endDate) {
            let dates;
            if (date === null) {
                this.params[startDate] = '';
                this.params[endDate] = '';
                this.searchHandler();
                return;
            }
            if (typeof date === 'string') {
                dates = date.split(' - ');
            } else if (date && date.hasOwnProperty('length')) {
                const firstDate = date[0];
                const secondDate = date[1];
                dates = [
                    `${firstDate.getFullYear()}-${(
                        '0' +
              (firstDate.getMonth() + 1)
                    ).substr(-2)}-${('0' + firstDate.getDate()).substr(-2)}`,
                    `${secondDate.getFullYear()}-${(
                        '0' +
              (secondDate.getMonth() + 1)
                    ).substr(-2)}-${('0' + secondDate.getDate()).substr(-2)}`
                ];
            }
            this.params[startDate] = +new Date(dates[0]);
            this.params[endDate] = +new Date(dates[1]);
            this.searchHandler();
        },
        getRemoteData ({fetch, dataKey, resultField, resultHandler}) {
            fetch().then(response => {
                let result = response;
                if (typeof response === 'object' && !this.isArray(response)) {
                    if (resultField.indexOf('.') !== -1) {
                        resultField.split('.').forEach(vv => {
                            result = result[vv];
                        });
                    } else {
                        result = response[resultField];
                    }
                }
                if (!result || !(result instanceof Array)) {
                    console.warn(
                        `The result of key:${resultField} is not Array. 接口返回的字段:${resultField} 不是一个数组`
                    );
                }
                if (resultHandler) {
                    this.selectOptions[dataKey] = result.map(resultHandler);
                } else {
                    this.selectOptions[dataKey] = result;
                }
            });
        },
        toggleAdvanced () {
            this.advanced = !this.advanced;
            const row = Math.ceil(this.forms.length / 3);
            if (!this.autoHeight) {
                this.$emit('folding', {opened: this.advanced, row});
            }
        },
        // 保证在最后一列
        getOffset (length, span) {
            const cols = 24 / span;
            return (cols - 1 - (length % cols)) * span;
        },
        check_num: debounce(function (name) {
            this.params[name] = this.params[name].match(/^\d*/g)[0];
        }, 600)
    }
};
</script>

<style lang="scss">
.search-table-form {
  background: #fff;
  padding: 20px 0 0 0;
  //    margin: 10px;
  .el-form-item {
    //margin-bottom: 10px;
    margin-left: -20px;
  }

  .search-btns {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding-bottom: 13px;

    a {
      font-size: 14px;
      color: #1890ff;
    }
  }

  .single-input {
    display: flex;
    justify-content: flex-end;

    .el-col {
      display: flex;
      align-items: center;
      justify-content: space-between;
      width: 600px;

      .el-form-item {
        flex: 1;
        margin-right: 20px;
      }
      &.el-col-md-16{
        width: 66.66667%;
      }
    }

    .search-btns {
      margin-bottom: 13px;
    }
    &.hasBackBtn{
      width: 100%;
      justify-content: space-between;
    }
  }
}
</style>
